package org.autumn.structure.stack;

/**
 * 测试代码
 */
public class AppTest {
    public static void main(String[] args) {
        System.out.println(exeExpression("50-100/2"));
    }

    /**
     * 执行一个简单的表达式 计算 + - * /
     * <p>
     * 遍历每一个元素
     * 数字押入数字栈,符号押入符号栈
     * 如果是符号,如果符号栈中为空,则直接入栈,如果不为空,需要与其对比优先级.
     * 如果符号小于等于栈中的, 则获取数字栈顶的两个数字和,获取符号栈中的栈顶的符号进行
     * 计算,并将当前的结果和符号压栈
     * 如果符号大于栈中的符号,则直接压栈
     * 如果不是一个符号,判断是否为最后一个字符,如果是则押入数字栈中
     * 如果不是获取下一个字符,判断是否为运算符，如果是则讲当前数字押入数字栈中,否则继续
     *
     * for example:
     *   System.out.println(exeExpression("50-100/2"));
     *   we got 0;
     */
    public static int exeExpression(String expression) {
        int length = expression.length();
        ArrayStack numStack = new ArrayStack(length);
        ArrayStack symbolStack = new ArrayStack(length);

        String val = "";
        for (int i = 0; i < length; i++) {
            char c = expression.charAt(i);
            // 是否为一个计算符号
            if (isCalcSymbol(c)) {
                if (symbolStack.isEmpty()) {
                    symbolStack.push(c);
                } else {
                    if (getPriorty(c) <= getPriorty((char) symbolStack.peek())) {
                        // 获取数字栈顶的两个数字
                        // 获取符号栈中的栈顶的符号
                        int result = calculate((int) numStack.pop(), (int) numStack.pop(), (char) symbolStack.pop());
                        // 把运算结果放入数据栈
                        numStack.push(result);
                        // 把当前符号押入符号栈
                        symbolStack.push(c);
                    }else {
                        symbolStack.push(c);
                    }
                }
            } else {
                val += c;
                if (i == length-1){
                    numStack.push(Integer.valueOf(val));
                }else {
                    char next = expression.charAt(i + 1);
                    if (isCalcSymbol(next)){
                        numStack.push(Integer.valueOf(val));
                        val = "";
                    }
                }
            }
        }
        // 计算剩下的符号
        while (!symbolStack.isEmpty()){
            int result = calculate((int) numStack.pop(), (int) numStack.pop(), (char) symbolStack.pop());
            numStack.push(result);
        }
        return (int) numStack.pop();
    }


    /**
     * 表达式的计算 + - * /
     * v1 为减数, v2为被减数
     * 这里因为后押入栈中的肯定是减数或者除数
     */
    public static int calculate(int v1, int v2, char symbol) {
        int result = 0;
        switch (symbol) {
            case '+':
                result = v2 + v1;
                break;
            case '-':
                result = v2 - v1;
                break;
            case '*':
                result = v2 * v1;
                break;
            case '/':
                result = v2 / v1;
                break;
            default:
                throw new RuntimeException("Unknown symbol " + symbol);
        }
        return result;
    }

    /**
     * 是否为一个运算符号
     * 这里只验证  + - * /
     */
    public static boolean isCalcSymbol(char symbol) {
        char[] symbols = {'+', '-', '*', '/'};
        for (int i = 0; i < symbols.length; i++) {
            if (symbols[i] == symbol) {
                return true;
            }
        }
        return false;
    }

    /**
     * 获取优先级
     */
    public static int getPriorty(char symbol) {
        return (symbol == '*' || symbol == '/') ? 1 : 0;
    }

    /**
     * 判断字符串是否是回文
     * 回文(正反读都一样的词语)
     * for example: "aba"
     * 通过栈来反转字符串
     */
    public static boolean isPalindrome(String val) {
        int length = val.length();
        ArrayStack<Character> stack = new ArrayStack<>(length);
        // 压栈
        for (int i = 0; i < length; i++) {
            stack.push(val.charAt(i));
        }
        StringBuilder sb = new StringBuilder();
        // 出栈
        for (int i = 0; i < length; i++) {
            sb.append(stack.pop());
        }
        return sb.toString().equals(val);
    }

    /**
     * 反转字符串,判断反转后的字符串是否等于目标字符
     */
    public static boolean isPalindrome2(String val) {
        char[] chars = val.toCharArray();
        StringBuilder sb = new StringBuilder();
        for (int i = chars.length - 1; i >= 0; i--) {
            sb.append(chars[i]);
        }
        return sb.toString().equals(val);
    }


}
